﻿using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Threading;
using Microsoft.Phone.Controls;
using Com.PhilChuang.Utils.Mobile;
using Microsoft.Phone.Shell;

namespace Com.PhilChuang.Utils.Mobile
{
	public static class AppExtensions
	{
		public static void Invoke (this Dispatcher d, Action a)
		{
			if (!d.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				d.BeginInvoke (() =>
				{
					a.Invoke ();
					mre.Set ();
				});
				mre.WaitOne ();
				return;
			}

			a.Invoke ();
		}

		public static T Invoke<T> (this Dispatcher d, Func<T> a)
		{
			if (!d.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				T result = default (T);
				d.BeginInvoke (() =>
				{
					result = a.Invoke ();
					mre.Set ();
				});
				mre.WaitOne ();
				return result;
			}

			return a.Invoke ();
		}

		/// <summary>
		/// Invokes the action using the Dispatcher if required, otherwise it does nothing
		/// </summary>
		/// <param name="d"></param>
		/// <param name="a"></param>
		/// <returns>whether or not the action was invoked</returns>
		public static bool InvokeIfRequired (this Dispatcher d, Action a)
		{
			if (!d.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				d.BeginInvoke (() =>
				{
					a.Invoke ();
					mre.Set ();
				});
				mre.WaitOne ();
				return true;
			}

			return false;
		}

		/// <summary>
		/// Invokes the action using the Dispatcher if required, otherwise it does nothing
		/// </summary>
		/// <param name="d"></param>
		/// <param name="a"></param>
		/// <param name="result"></param>
		/// <returns>whether or not the action was invoked</returns>
		public static bool InvokeIfRequired<T> (this Dispatcher d, Func<T> a, ref T result)
		{
			if (!d.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				T result2 = default (T);
				d.BeginInvoke (() =>
				{
					result2 = a.Invoke ();
					mre.Set ();
				});
				mre.WaitOne ();
				result = result2;
				return true;
			}

			return false;
		}

		public static T InvokeGet<T> (this UserControl self, Func<T> getter)
		{
			if (!self.Dispatcher.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				T value = default (T);
				self.Dispatcher.Invoke (() =>
				{
					value = getter ();
					mre.Set ();
				}
					);
				mre.WaitOne ();
				return value;
			}

			return getter ();
		}

		public static void InvokeSet<T> (this UserControl self, Action<T> setter, T value)
		{
			if (!self.Dispatcher.CheckAccess ())
			{
				var mre = new ManualResetEvent (false);
				self.Dispatcher.Invoke (() =>
				{
					setter (value);
					mre.Set ();
				}
					);
				mre.WaitOne ();
				return;
			}

			setter (value);
		}

		public static IEnumerable<UIElement> GetAllChildren (this Panel self)
		{
			self.ThrowIfNull ("self");
			foreach (var child in self.Children)
			{
				yield return child;
				var p = child as Panel;
				if (p != null)
				{
					foreach (var child2 in p.GetAllChildren ())
					{
						yield return child2;
					}
				}
			}
			yield break;
		}

		public static void DisplayErrorMessage (this PhoneApplicationPage self, string text, string caption)
		{
			self.DisplayMessage (text, caption);
		}

		public static void DisplayMessage (this PhoneApplicationPage self, string text, string caption)
		{
			if (!self.Dispatcher.CheckAccess ())
			{
				self.Dispatcher.Invoke (() => self.DisplayMessage (text, caption));
				return;
			}

			MessageBox.Show (text, caption, MessageBoxButton.OK);
		}

		/// <summary>
		/// Displays a yes/no dialog to the user
		/// </summary>
		/// <param name="self"></param>
		/// <param name="text"></param>
		/// <param name="caption"></param>
		/// <returns>user selected yes</returns>
		public static bool DisplayYesNoChoice (this PhoneApplicationPage self, string text, string caption)
		{
			if (!self.Dispatcher.CheckAccess ())
			{
				return self.Dispatcher.Invoke (() => self.DisplayYesNoChoice (text, caption));
			}

			return MessageBox.Show (text, caption, MessageBoxButton.OKCancel) == MessageBoxResult.OK;

			// TODO see http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.popup%28VS.95%29.aspx
		}

		public static void SetApplicationBarEnabled (this PhoneApplicationPage self, bool enabled)
		{
			if (self.ApplicationBar == null) return;
			foreach (ApplicationBarIconButton btn in self.ApplicationBar.Buttons)
				btn.IsEnabled = enabled;
			foreach (ApplicationBarMenuItem menuitem in self.ApplicationBar.MenuItems)
				menuitem.IsEnabled = enabled;
		}
	}
}
